#include <windows.h>

#include "lib.h"
#include "patch.h"
#include "file.h"

File::File(FileCB* CB)
{
	handle = INVALID_HANDLE_VALUE;
	cb = CB;
}

File::~File()
{
	close();
}

bool8
File::open(const String& Filename)
{
	handle = CreateFile(Filename, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
	if (handle == INVALID_HANDLE_VALUE)
		return false;

	ZeroMemory(over, sizeof(OVERLAPPED));

	return true;
}

void
File::close()
{
	if (handle != INVALID_HANDLE_VALUE)
	{
		CloseHandle(handle);
		handle = INVALID_HANDLE_VALUE;
	}
}

bool8
File::seek(int32 position)
{
	if (handle != INVALID_HANDLE_VALUE)
	{
		if(over)
		{
			// overlapped files don't have the luxury of having the 
			//  operating system keep track of the file pointer for
			//  them, so they keep this info in the overlapped structure.
			over->Offset 		= position;
			over->OffsetHigh 	= 0;
		}
		return true;
	}
	return false;
}

void
File::read(uint8* Buf, int32 Amt)
{
	BOOL result;
	DWORD err;

	ASSERT(1 == HasOverlappedIoCompleted(over));

	result = ReadFile(handle, Buf, Amt, NULL, over);
	err = GetLastError();

	if (result)
		return;

	if (err == ERROR_IO_PENDING)
		return;

	over->Internal = 0;

	// at this point it's safe to call CB since no other i/o is
	// posted and can be processed.  (This is only true if max of ONE
	// i/o req is ever allowed at any one time for a single File obj)
	// NOTE:  if >1 i/o req is desired, then must synchronize ALL
	// calls to CB
	//
	if (cb)
	{
		if (err == ERROR_HANDLE_EOF)
			cb->fileEOF();
		else
			cb->fileErr(err);
	}
}

void
File::ioDone(DWORD Amt)
{
	DWORD was = over->Offset;

	over->Offset += Amt;
	if (over->Offset < was)		// wrapped... >4GB file
		++over->OffsetHigh;

	if (cb)
		cb->fileIn(Amt);
}

void
File::ioErr(DWORD Err)
{
	if (cb)
    {
        // kharmon.  04-05-07.  #19307.  Need to handle EOF separately from other errors.
		if (Err == ERROR_HANDLE_EOF)
			cb->fileEOF();
		else
			cb->fileErr(Err);
    }
}

uint32 
File::getSize()
{
	if(handle != INVALID_HANDLE_VALUE)
	{
		return GetFileSize(handle, NULL);
	}
	else
	{
		return 0;
	}
}

